<?php

namespace pmvc\data\sql;

use stdClass;
use Exception;

class OrmUtil {

	/**
	 * Delets objects on the givne {@link DataSource} on
	 * the given table identified by the given ids using
	 * the optional id field.
	 * @param DataSource $ds
	 * @param string $table
	 * @param mixed $ids
	 * @param string $idField
	 */
	public static function deleteObjects(DataSource $ds, $table, $ids, $idField="id") {
		$sql = "delete from ".$table." where ".$idField;
		$sql .= is_array($ids) ? "  in({0})" : "={0}";
		return $ds->updateParams($sql, Array($ids));
	}

	/**
	 * Executes an insert statement on the given {@link DataSource}
	 * on the given table using the given object limitted to the
	 * optional field names.
	 * @param DataSource $ds
	 * @param string $table
	 * @param object $object
	 * @param array $fieldNames
	 * @throws Exception on error
	 */
	public static function insertObject(DataSource $ds, $table, $object, $idField="id", Array $fieldNames=Array()) {
		$object = self::object($object);
		$vars = get_object_vars($object);
		if (empty($fieldNames)) {
			$fieldNames = array_keys($vars);
		}
		$sqlColumns = "";
		$sqlValues = "";
		foreach ($fieldNames as $fieldName) {
			if ($fieldName==$idField && !isset($vars[$idField])) {
				continue;
			}
			$sqlColumns .= $fieldName.",";
			$sqlValues .= "{".$fieldName."},";
		}
		$sql = "insert into ".$table." (".substr($sqlColumns, 0, strlen($sqlColumns)-1).") "
			."values (".substr($sqlValues, 0, strlen($sqlValues)-1).")";
		$values = array_fill_keys($fieldNames, null);
		return $ds->updateParams($sql, array_merge($values, $vars));
	}

	/**
	 * Executes an update statement on the given {@link DataSource}
	 * on the given table using the given object identified by the
	 * optional id field limitted to the optional field names.
	 * @param DataSource $ds
	 * @param string $table
	 * @param object $object
	 * @param string $idField
	 * @param array $fieldNames
	 * @throws Exception on error
	 */
	public static function updateObject(DataSource $ds, $table, $object, $idField="id", Array $fieldNames=Array()) {
		$object = self::object($object);
		$vars = get_object_vars($object);
		if (!array_key_exists($idField, $vars)) {
			throw new Exception("Unable to find idField on object for updating");
		}
		if (empty($fieldNames)) {
			$fieldNames = array_keys($vars);
		}
		$sql = "update ".$table." set ";
		foreach ($fieldNames as $fieldName) {
			if ($fieldName==$idField) {
				continue;
			}
			$sql .= $fieldName."={".$fieldName."},";
		}
		$sql = substr($sql, 0, strlen($sql)-1)." where ".$idField."={".$idField."}";
		$values = array_fill_keys($fieldNames, null);
		return $ds->updateParams($sql, array_merge($values, $vars));
	}

	/**
	 * Updates or inserts the given object.
	 * @param DataSource $ds the
	 * @param unknown_type $table
	 * @param unknown_type $object
	 * @param unknown_type $idField
	 * @param array $fieldNames
	 * @throws Exception
	 */
	public static function insertOrUpdate(DataSource $ds, $table, $object, $idField="id", Array $fieldNames=Array()) {
		$object = self::object($object);
		$vars = get_object_vars($object);
		if (empty($fieldNames)) {
			$fieldNames = array_keys($vars);
		}
		if (!array_key_exists($idField, $vars)) {
			return self::insertObject($ds, $table, $object, $idField, $fieldNames);
		} else {
			$obj = $ds->querySingle("select ".$idField." from ".$table." where ".$idField."={0}", $vars[$idField]);
			return ($obj)
				? self::updateObject($ds, $table, $object, $idField, $fieldNames)
				: self::insertObject($ds, $table, $object, $idField, $fieldNames);
		}
	}

	/**
	 * Converts the given value to an object
	 * if needed. 
	 * @param mixed $obj
	 */
	public static function object($obj) {
		if (is_object($obj)) {
			return $obj;
		} else if (is_array($obj)) {
			$ret = new stdClass();
			foreach ($obj as $key=>$val) {
				$ret->$key = $val;
			}
			return $ret;
		} else {
			throw Exception("Unknown type to convert to object");
		}
	}

}

?>